#include "musicplayer.h"
#include "math.h"
//#include <windows.h>

bool musicPlayer::verCompatibility()
{
    if(HIWORD(BASS_GetVersion())!=BASSVERSION)
    {
        this->messageBoxShow(3, "Version error!", "ERROR:\t You have bad version of bass.dll.\nTry another version to fix this error.");
        return false;
    }
    else
        return true;
}

void musicPlayer::stopBASS()
{
    BASS_Free();
}

void musicPlayer::freeStream(HSTREAM stream)
{
    BASS_StreamFree(stream);
}

musicPlayer::musicPlayer()
{
    eq = new BASS_DX8_PARAMEQ();
    ch = new BASS_DX8_CHORUS();
    echo = new BASS_DX8_ECHO();
    fl = new BASS_DX8_FLANGER();
    reverb = new BASS_DX8_REVERB();
    gar = new BASS_DX8_GARGLE();
    dist = new BASS_DX8_DISTORTION();
}

bool musicPlayer::initBASS()
{
    if (!BASS_Init (-1, 48000, BASS_DEVICE_3D , 0, NULL))
    {
        this->messageBoxShow(3, "Error!", "Can't initialize BASS!");
        BASS_Free();
        return false;
    }
    else
        return true;
}

double musicPlayer::getStreamLength(HSTREAM stream)
{
    QWORD length = BASS_ChannelGetLength(stream, BASS_POS_BYTE);
    return BASS_ChannelBytes2Seconds(stream, length);
}

void musicPlayer::streamSetPos(HSTREAM stream, double sec)
{
    QWORD position = BASS_ChannelSeconds2Bytes(stream, sec);
    BASS_ChannelSetPosition(stream, position, BASS_POS_BYTE);
}

double musicPlayer::streamGetPos(HSTREAM stream)
{
    QWORD position = BASS_ChannelGetPosition(stream, BASS_POS_BYTE);
    return BASS_ChannelBytes2Seconds(stream, position);
}

void musicPlayer::messageBoxShow(int type, QString title, QString text)
{
    switch(type)
    {
        case 1:
        {
            QMessageBox::information(0, title, text);
            break;
        }
        case 2:
        {
            QMessageBox::warning(0, title, text);
            break;
        }
        case 3:
        {
            QMessageBox::critical(0, title, text);
            break;
        }
    }
}

HSTREAM musicPlayer::createStream(QString filename)
{
    filename.replace("\\","/");
    QByteArray ar = filename.toLocal8Bit();
    char* name = ar.data();
    HSTREAM stream;
    stream = BASS_StreamCreateFile(FALSE, name, 0, 0, 0);
    if (!stream)
    {
        /* ...error processing... */
        return NULL;
    }
    return stream;
}

int musicPlayer::checkStream(HSTREAM stream)
{
    switch(BASS_ChannelIsActive(stream))
    {
        case BASS_ACTIVE_STOPPED:
        {
            return 0;
            break;
        }
        case BASS_ACTIVE_PLAYING:
        {
            return 1;
            break;
        }
        case BASS_ACTIVE_PAUSED:
        {
            return 2;
            break;
        }
        case BASS_ACTIVE_STALLED:
        {
            return 3;
            break;
        }
        default:
        {
            return -1;
            break;
        }
    }
}

void musicPlayer::playStream(HSTREAM stream, bool restart)
{
    if(BASS_ChannelIsActive(stream) != BASS_ACTIVE_PLAYING)
        BASS_ChannelPlay(stream, restart);
    else
        return;
}

void musicPlayer::pauseStream(HSTREAM stream)
{
    if(BASS_ChannelIsActive(stream) != BASS_ACTIVE_PAUSED)
        BASS_ChannelPause(stream);
    else
        return;
}

void musicPlayer::stopStream(HSTREAM stream)
{
    if(BASS_ChannelIsActive(stream) != BASS_ACTIVE_STOPPED)
    {
        BASS_ChannelStop(stream);
    }
}

void musicPlayer::volumeEffect(HSTREAM stream, int position)
{
    while (position != 0)
    {
        BASS_ChannelSetAttribute(stream, BASS_ATTRIB_VOL, (float)position/100);
        position--;
        Sleep(5);
    }

}

void musicPlayer::setBalance(HSTREAM stream, int position)
{
    BASS_ChannelSetAttribute(stream, BASS_ATTRIB_PAN, (float)position/100);
}

void musicPlayer::setVolume(HSTREAM stream, int position)
{
    BASS_ChannelSetAttribute(stream, BASS_ATTRIB_VOL, (float)position/100);
}

int musicPlayer::equalizerSettings(int center)
{
//    18 level equalizer
    switch(center)
    {
        case 31:
        {
            return 0;
            break;
        }
        case 63:
        {
            return 1;
            break;
        }
        case 87:
        {
            return 2;
            break;
        }
        case 125:
        {
            return 3;
            break;
        }
        case 175:
        {
            return 4;
            break;
        }
        case 250:
        {
            return 5;
            break;
        }
        case 350:
        {
            return 6;
            break;
        }
        case 500:
        {
            return 7;
            break;
        }
        case 700:
        {
            return 8;
            break;
        }
        case 1000:
        {
            return 9;
            break;
        }
        case 1400:
        {
            return 10;
            break;
        }
        case 2000:
        {
            return 11;
            break;
        }
        case 2800:
        {
            return 12;
            break;
        }
        case 4000:
        {
            return 13;
            break;
        }
        case 5600:
        {
            return 14;
            break;
        }
        case 8000:
        {
            return 15;
            break;
        }
        case 11200:
        {
            return 16;
            break;
        }
        case 16000:
        {
            return 17;
            break;
        }
        default:
        {
            //return -1;
            break;
        }
    }
}

void musicPlayer::equalizerStart(int center, int gain)
{
    eq->fGain = gain;
    eq->fBandwidth = 4;
    eq->fCenter = center;
    BASS_FXSetParameters(equalize[equalizerSettings(center)], eq);
}


void musicPlayer::equalizerInit(HSTREAM stream)
{
    for(int i = 0; i<18; i++)
    {
        equalize[i] = BASS_ChannelSetFX(stream, BASS_FX_DX8_PARAMEQ, 1);
    }
}

void musicPlayer::equalizerRemove(DWORD handle)
{
    for(int i = 0; i<18; i++)
    {
        BASS_ChannelRemoveFX(handle, equalize[i]);
    }
}

void musicPlayer::removeEffect(DWORD handle, int num)
{
    BASS_ChannelRemoveFX(handle, effects[num]);
}

void musicPlayer::effectsInit(HSTREAM stream, int num)
{
    switch(num)
    {
        case 0:
        {
            effects[0] = BASS_ChannelSetFX(stream, BASS_FX_DX8_CHORUS, 1);
            break;
        }
        case 1:
        {
            effects[1] = BASS_ChannelSetFX(stream, BASS_FX_DX8_ECHO, 1);
            break;
        }
        case 2:
        {
            effects[2] = BASS_ChannelSetFX(stream, BASS_FX_DX8_FLANGER, 1);
            break;
        }
        case 3:
        {
            effects[3] = BASS_ChannelSetFX(stream, BASS_FX_DX8_REVERB,1);
            break;
        }
        case 4:
        {
            effects[4] = BASS_ChannelSetFX(stream, BASS_FX_DX8_GARGLE, 1);
            break;
        }
        case 5:
        {
            effects[5] = BASS_ChannelSetFX(stream, BASS_FX_DX8_DISTORTION, 1);
            break;
        }
        default:
            break;
    }
}

void musicPlayer::chorusSetParam(float mix, float deep, float feedback, float frequency, float delay, int phase, int wf)
{
    switch(phase)
    {
        case 1:
        {
            ch->lPhase = BASS_DX8_PHASE_NEG_180;
            break;
        }
        case 2:
        {
            ch->lPhase = BASS_DX8_PHASE_NEG_90;
            break;
        }
        case 3:
        {
            ch->lPhase = BASS_DX8_PHASE_ZERO;
            break;
        }
        case 0:
        {
            ch->lPhase = BASS_DX8_PHASE_90;
            break;
        }
        case 4:
        {
            ch->lPhase = BASS_DX8_PHASE_180;
            break;
        }
        default:
            break;
    }

    switch(wf)
    {
        case 1:
        {
            ch->lWaveform = 0;
            break;
        }
        case 0:
        {
            ch->lWaveform = 1;
            break;
        }
        default:
            break;
    }

    ch->fWetDryMix = mix;
    ch->fDepth = deep;
    ch->fFeedback = feedback;
    ch->fFrequency = frequency;
    ch->fDelay = delay;

    BASS_FXSetParameters(effects[0], ch);
}

void musicPlayer::echoSetParam(float mix, float feedback, float rightD, float leftD, bool swap)
{
    echo->fWetDryMix = mix;
    echo->fFeedback = feedback;
    echo->fRightDelay = rightD;
    echo->fLeftDelay = leftD;
    echo->lPanDelay = swap;

    BASS_FXSetParameters(effects[1], echo);
}

void musicPlayer::flangerSetParam(float mix, float deep, float feedback, float frequency, float delay, int phase, int wf)
{
    switch(phase)
    {
        case 1:
        {
            fl->lPhase = BASS_DX8_PHASE_NEG_180;
            break;
        }
        case 2:
        {
            fl->lPhase = BASS_DX8_PHASE_NEG_90;
            break;
        }
        case 0:
        {
            fl->lPhase = BASS_DX8_PHASE_ZERO;
            break;
        }
        case 3:
        {
            fl->lPhase = BASS_DX8_PHASE_90;
            break;
        }
        case 4:
        {
            fl->lPhase = BASS_DX8_PHASE_180;
            break;
        }
        default:
            break;
    }

    switch(wf)
    {
        case 1:
        {
            fl->lWaveform = 0;
            break;
        }
        case 0:
        {
            fl->lWaveform = 1;
            break;
        }
        default:
            break;
    }

    fl->fWetDryMix = mix;
    fl->fDepth = deep;
    fl->fFeedback = feedback;
    fl->fFrequency = frequency;
    fl->fDelay = delay;

    BASS_FXSetParameters(effects[2], fl);
}

void musicPlayer::reverbSetParam(float gain, float mix, float time, float HFtime)
{
    reverb->fInGain = gain;
    reverb->fReverbMix = mix;
    reverb->fReverbTime = time;
    reverb->fHighFreqRTRatio = HFtime;

    BASS_FXSetParameters(effects[3], reverb);
}

void musicPlayer::gargleSetParam(DWORD rate, int wf)
{
    gar->dwRateHz = rate;
    switch(wf)
    {
        case 0:
        {
            gar->dwWaveShape = 0;
            break;
        }
        case 1:
        {
            gar->dwWaveShape = 1;
            break;
        }
        default:
            break;
    }

    BASS_FXSetParameters(effects[4], gar);
}

void musicPlayer::distortionSetParam(float gain, float edge, float freq, float bw, float plc)
{
    dist->fGain = gain;
    dist->fEdge = edge;
    dist->fPostEQCenterFrequency = freq;
    dist->fPostEQBandwidth = bw;
    dist->fPreLowpassCutoff = plc;

    BASS_FXSetParameters(effects[5], dist);
}

void musicPlayer::sampRateSet(DWORD handle, float freq)
{
    BASS_ChannelSetAttribute(handle, BASS_ATTRIB_FREQ, freq);
}
